package org.vectrics.skill.struts;

import java.util.Collection;
import java.util.Iterator;

import org.apache.log4j.Category;
import org.vectrics.SystemException;
import org.vectrics.common.tree.TreeHelper;
import org.vectrics.recruiter.RecruitServiceLocator;
import org.vectrics.recruiter.user.RecruitUserProfile;
import org.vectrics.skill.Skill;
import org.vectrics.skill.SkillException;
import org.vectrics.skill.SkillRating;
import org.vectrics.skill.SkillRatingSet;
import org.vectrics.skill.SkillSetUtil;
import org.vectrics.struts.Request;
import org.vectrics.struts.VectricsActionData;
import org.vectrics.struts.VectricsStrutsAction;


abstract public class SaveSkillsActionAbstract extends VectricsStrutsAction {
    private static Category log = Category.getInstance(SaveSkillsActionAbstract.class);
    public static String ACTION_NAME = "save_detail_skills";
    private RecruitUserProfile userProfile = null;
    private Collection skillSet = null;
    private boolean usingWizard = true;
    private int currentLevel = 0;
//    private boolean needMoreDetails = false;
//    private boolean save = false;
    public static String MAPPING_NEXT_LEVEL = "next";
    public static String MAPPING_SUMMARY = "summary";
    public static String MAPPING_PREVIOUS = "previous";
    public static String MAPPING_DONE = "done";
    
	private boolean isThereMoreToEnter = false;
	private boolean nextButtonPressed = false;
	private boolean previousButtonPressed = false;
    private Collection unenteredSkillsAtThisLevel = null;
    
    
    abstract protected void saveSkillRatingSet(Request request, SkillRatingSet ratingSet) throws SkillException;
    abstract protected boolean getKeepAllRatings();
    
    final  protected SkillRatingSet getSkillRatingSet(Request request) throws SkillException {
    	SkillRatingSet set = SkillWebUtils.getSkillRatingSet(request);
    	if (set == null) {
    		throw new SkillException("SkillRatingSet was not previously attached to session attribute - make sure PrepareWizardAction is called first");
    	}
    	return(set);
    }
    
    
    
    
    public String doExecute(VectricsActionData actionData) {
    	String forwardCode = "success";
    	log.debug("execute() called.");

    	Skill rootSkill = null;
    	try {
    		rootSkill = RecruitServiceLocator.getSkillProvider().getRootSkill();
    		if (rootSkill == null) {
    			throw new SkillException("Attempt to find root skill returned null");
    		}
    	}
    	catch (org.vectrics.skill.SkillException se) {
    		log.error("SkillException finding root skill or getting provider instance", se);
    		throw new SystemException("SkillException finding root skill or getting provider instance", se);
    	}

    	log.debug("fill list of unentered skills with all skills on this level, later skills will be removed from this list as this class determines that there was a non-zero rating entered for that skill.");
        unenteredSkillsAtThisLevel = TreeHelper.getChildrenAtLevel(rootSkill, currentLevel);

    	String levelParam = actionData.getRequest().getParameter("level");
    	if (levelParam != null)
    		currentLevel = Integer.parseInt(levelParam);
    	else 
    		currentLevel = 0;
    	
    	SkillRatingForm skillForm = (SkillRatingForm)actionData.getForm();
    	
    	if (skillForm != null) {
    		//currentLevel = skillForm.getLevel();
    	}
    	else {
    		skillForm = new SkillRatingForm();
    		actionData.setForm(skillForm);
    	}
    	skillForm.setLevel(currentLevel + 1);
    	
    	if (actionData.wasButtonPressed("next")) {
    		log.debug("Next button pressed");
    		nextButtonPressed = true;
    		//skillForm.setLevel(currentLevel + 1);
    		SkillWebUtils.setLevel(actionData.getRequest(), currentLevel + 1);
    		forwardCode = MAPPING_NEXT_LEVEL;
    	}
    	
    	if (actionData.wasButtonPressed("previous")) {
    		log.debug("Prev button pressed");
    		previousButtonPressed = true;
    		//skillForm.setLevel(cuvrrentLevel - 1);
    		SkillWebUtils.setLevel(actionData.getRequest(), currentLevel - 1);
    		isThereMoreToEnter = true;
    		forwardCode = MAPPING_PREVIOUS;
    	}
    	
    	
    	
        SkillRatingSet skillRatingSet = null;
        try {
        	skillRatingSet = getSkillRatingSet(actionData.getRequest());
        }
        catch (SkillException se) {
        	log.error("SkillException finding ratings from session", se);
        	throw new SystemException("SkillException finding ratings from session", se);
        }
        
        
        
        
        
        log.debug("doPerform() - current level = " + currentLevel);
  //      needMoreDetails = false;

        
        skillSet = skillRatingSet.findAllSkillRatings();

        if (isThereMoreToEnter) {
            usingWizard = true;
        }
        
        
        
        try {
            // Remove all the skills for the level just submitted,  this procedure
            // will add the ones the user selected
            //if ((usingWizard) && (currentLevel >= 0)) {
        	if (!getKeepAllRatings()) {
        		SkillSetUtil util = new SkillSetUtil(skillRatingSet, rootSkill);                
        		util.removeSkillsForLevel(currentLevel);
        	}
            readFormSkillEntries(actionData.getRequest(), rootSkill, skillRatingSet);
        }
        catch (Exception ex) {
            log.error("Exception in doPerform: " , ex);
            throw new SystemException("Exception in doPerform: " , ex);
        }
        
        
        if (log.isDebugEnabled()) {
        	Iterator iter = unenteredSkillsAtThisLevel.iterator();
        	while (iter.hasNext()) {
        		Skill skill = (Skill)iter.next();
        		log.debug("Unentered skill: " + skill.getCode());
        	}
        }
        
        // Remove ratings under skills which were not entered
        try {
        	skillRatingSet.clearSkillBranches(unenteredSkillsAtThisLevel);
        }
        catch (Exception ex) {
        	log.error("Exception clearing skill branches", ex);
        	throw new SystemException("Exception clearing skill branches", ex);
        }
        

        if (isThereMoreToEnter == false) {
        	forwardCode = MAPPING_DONE;
        	try {
        		log.debug("No more skills to enter, saving...");
        		this.saveSkillRatingSet(actionData.getRequest(), skillRatingSet);
        	
        		log.debug("Wiping out session attributes relating to editing these skills...");
//        		SkillWebUtils.setSkillRatingSet(request.getSession(), null);
        		
        	}
        	catch (SkillException se) {
        		log.error("SkillException saving ratings", se);
        		throw new SystemException("SkillException saving ratings", se);
        	}
        }
        
        if (log.isDebugEnabled()) {
        	log.debug("After saving skill set -  all ratings = \r\n" + skillRatingSet.toString());
        }
        
        log.debug("Result forward = " + forwardCode);
        return (forwardCode);
    }

    protected void readFormSkillEntries(Request request, Skill rootSkill, SkillRatingSet skillRatingSet) {
	    Iterator<String> paramEnum = request.getParameterNames().iterator();
	    
	    while (paramEnum.hasNext()) {
	        String paramName = (String)paramEnum.next();
	        String value = request.getParameter(paramName);
	        log.debug("doPerform() - looking at param -  name : " + paramName);                        
	        log.debug("doPerform() - looking at param - value : " + value);                        
	
	        
	        if (paramName.startsWith("yrs_")) {
	            log.debug("doPerform() - yrs_ param found.  Setting skill years.");
	            if  (value.trim().length() > 0) {
	                        
	                int valueInt = 0;
	                try {
	                    valueInt = Integer.parseInt(value);
	                }
	                catch (Exception ex) {
	                    log.error(ex);
	                    valueInt = -1;
	                }
	                        
	                if (valueInt > 0) {
	                    log.debug("doPerform() - yrs rating found: " + paramName);
	                    String skillCode = paramName.substring(4);
	                    Skill skill = (Skill)TreeHelper.findNode(rootSkill, skillCode);
	                    
	                    if (skill != null) {
	                    	unenteredSkillsAtThisLevel.remove(skill);
	                    	if (isThereMoreToEnter == false) {
	                        	if (skill.getChildren().size() > 0) {
	                        		isThereMoreToEnter = true;
	                        		log.debug("Selected skill has children, there is more to enter - detected in years setting");
	                        	}
	                        }
	                        SkillRating rating = skillRatingSet.findSkillRating(skill);
	                        if (rating == null) {
	                            log.debug("doPerform() - creating new skill rating.");
	                            rating = skillRatingSet.addRating(skill);
	                            rating.setLevel("0");
	                            
	                            if (skill.getChildren().size() > 0) {
	                            	isThereMoreToEnter = true;
	                            	log.debug("Selected skill has children, there is more to enter");
	                            }
	                        }
	                        log.debug("Setting yrs to " + value);
	                        rating.setLevel(value);
	                    }
	                    else {
	                        log.error("doPerform() - Could not find skill for param: "
	                                + paramName + "  Code = " + skillCode);
	                    };
	                }
	            }
	            else {
	                log.debug("doPerform() - yrs_ param had blank value - ignored");
	            }
	        }
	        else if (paramName.startsWith("lvl_")) {
	            if (value.trim().length() > 0) { 
	                log.debug("doPerfom() - 'lvl-*** - rating level found.");
	                String skillCode = paramName.substring(4);
	                Skill skill = (Skill)TreeHelper.findNode(rootSkill, skillCode);
	                if (skill != null) {
	                    SkillRating rating = skillRatingSet.findSkillRating(skill);
	                    int ratingLevel = Integer.parseInt(value);
	                    if ((rating == null) && (ratingLevel > 0)) {
	                    	unenteredSkillsAtThisLevel.remove(skill);
	                    	if (isThereMoreToEnter == false) { 
	                    		if (skill.getChildren().size() > 0) {
	                    			isThereMoreToEnter = true;
	                    			log.debug("doPerform() - isThereMoreToEnter set to true while setting rating level.");
	                    			
	                    		}
	                    	}
	                    	
	                        log.debug("doPerform() - found lvl - creating new skill rating.");
	                        
	                        rating = skillRatingSet.addRating(skill);
	
	                        if (ratingLevel <= 0)
	                            rating.setLevel("0");
	                        else 
	                            rating.setLevel("0");
	                        rating.setSkill(skill);
	                    }
	                    
	                    if (rating != null) {
	                        log.debug("Setting lvl to " + value);
	                        rating.setLevel(value);
	                    }
	                    
	                }
	                else {
	                    log.error("doPerform() - Could not find skill for param: "
	                            + paramName + "  Code = " + skillCode);
	                };
	            }
	            else {
	                log.debug("doPerform() - lvl_ param had blank value.  Ignored.");
	            }
	        }
	        else if (paramName.startsWith("yn_")) {
	            String skillCode = paramName.substring(3);
	            log.debug("doPerform() - checked: " + skillCode);
	            Skill skill = (Skill)TreeHelper.findNode(rootSkill, skillCode);
	            
	            if (skill != null) {
	            	unenteredSkillsAtThisLevel.remove(skill);
	            	
	            	if (isThereMoreToEnter == false) { 
	            		if (skill.getChildren().size() > 0) {
	            			log.debug("doPerform() - isThereMoreToEnter set to true while setting yes/no to yes.");
	            			isThereMoreToEnter = true;
	            		}
	            		else {
	            			log.debug("skill check as 'yes' doesn't have children");
	            		}
	            	}
	            	
	                SkillRating rating = skillRatingSet.findSkillRating(skill);
	                if (rating == null) {
	                	log.debug("did not find existing rating, creating new one.");
	                    rating = skillRatingSet.addRating(skill);
	                    rating.setLevel("y");
	                } else {
	                	rating.setLevel("y");
	                }
	            }
	            else {
	                log.error("doPerform() - Could not find skill for param: "
	                        + paramName + "  Code = " + skillCode);
	            };
	        }
	        else if (paramName.startsWith("children_")) {
	            String skillCode = paramName.substring(9);
	            log.debug("doPerform() - view children checked, skill = " + skillCode);
	            Skill skill = (Skill)TreeHelper.findNode(rootSkill, skillCode);
	            
	            if (skill != null) {
	            	unenteredSkillsAtThisLevel.remove(skill);
	            	if (isThereMoreToEnter == false) { 
	            		if (skill.getChildren().size() > 0) {
	            			log.debug("doPerform() - isThereMoreToEnter set to true while setting 'view children'.");
	            			isThereMoreToEnter = true;
	            		}
	            		else {
	            			log.debug("skill check as 'view children' doesn't have children");
	            		}
	            	}
	            	SkillRating rating = skillRatingSet.findSkillRating(skill);
	                if (rating == null) {
	                    rating = skillRatingSet.addRating(skill);
	                    rating.setLevel(null);
	                    rating.setSkill(skill);
	                }
	                
	                rating.setViewChildren(new Boolean(true));
	            }
	            else {
	                log.error("doPerform() - Could not find skill for param: "
	                        + paramName + "  Code = " + skillCode);
	            };
	        }
	        else {
	            log.debug("doPerform() - param did not match a pattern: " + paramName);
	        }
	        
	    }
    }
}